package cn.com.anysdk.redis.exception;

import cn.com.anysdk.redis.event.RedisErrorEvent;
import cn.com.anysdk.redis.event.RedisEventManager;
import lombok.extern.slf4j.Slf4j;

/**
 * Redis异常处理器
 */
@Slf4j
public class RedisExceptionHandler {

    private final RedisEventManager eventManager;

    public RedisExceptionHandler(RedisEventManager eventManager) {
        this.eventManager = eventManager;
    }

    /**
     * 处理异常
     *
     * @param e 异常对象
     * @param source 事件源
     * @param environment 当前环境
     * @throws RedisException 处理后的Redis异常
     */
    public void handleException(Throwable e, Object source, String environment) throws RedisException {
        RedisException redisException = convertException(e);

        // 确定错误类型
        RedisErrorEvent.ErrorType errorType = determineErrorType(redisException);

        // 创建并发布错误事件
        RedisErrorEvent errorEvent = new RedisErrorEvent(
                source,
                environment,
                errorType,
                redisException.getMessage(),
                redisException,
                redisException.getErrorCode()
        );

        eventManager.fireErrorEvent(errorEvent);

        // 根据错误类型决定是否重新抛出异常
        if (shouldRethrow(errorType)) {
            throw redisException;
        }
    }

    /**
     * 将普通异常转换为Redis异常
     *
     * @param e 原始异常
     * @return Redis异常
     */
    private RedisException convertException(Throwable e) {
        if (e instanceof RedisException) {
            return (RedisException) e;
        }

        // 根据异常类型和消息进行分类
        String message = e.getMessage();
        if (message == null) {
            message = e.getClass().getName();
        }

        // 连接相关异常
        if (message.contains("connection") || message.contains("timeout") ||
            message.contains("network") || message.contains("refused")) {
            if (message.contains("timeout")) {
                return new RedisConnectionException.TimeoutException("连接超时: " + message, e);
            } else if (message.contains("auth") || message.contains("password")) {
                return new RedisConnectionException.AuthenticationException("认证失败: " + message, e);
            } else {
                return new RedisConnectionException.NetworkException("网络异常: " + message, e);
            }
        }

        // 命令相关异常
        if (message.contains("command") || message.contains("syntax") ||
            message.contains("argument") || message.contains("type")) {
            if (message.contains("syntax")) {
                return new RedisCommandException.SyntaxException("命令语法错误: " + message, e);
            } else if (message.contains("type")) {
                return new RedisCommandException.TypeException("命令类型错误: " + message, e);
            } else {
                return new RedisCommandException.ExecutionException("命令执行错误: " + message, e);
            }
        }

        // 阿里云特有异常
        if (message.contains("Aliyun") || message.contains("aliyun") ||
            message.contains("quota") || message.contains("permission")) {
            if (message.contains("quota")) {
                return new AliyunRedisException.QuotaLimitException("阿里云配额限制: " + message, e);
            } else if (message.contains("permission") || message.contains("denied")) {
                return new AliyunRedisException.PermissionDeniedException("阿里云权限不足: " + message, e);
            } else if (message.contains("instance") && message.contains("not found")) {
                return new AliyunRedisException.InstanceNotFoundException("阿里云实例不存在: " + message, e);
            } else if (message.contains("VPC") || message.contains("vpc")) {
                return new AliyunRedisException.VpcNetworkException("阿里云VPC网络异常: " + message, e);
            } else {
                return new AliyunRedisException("阿里云Redis异常: " + message, e);
            }
        }

        // 环境相关异常
        if (message.contains("environment") || message.contains("config")) {
            if (message.contains("missing") || message.contains("not found")) {
                return new RedisEnvironmentException.ConfigMissingException("配置缺失: " + message, e);
            } else if (message.contains("undefined")) {
                return new RedisEnvironmentException.UndefinedEnvironmentException("环境未定义: " + message, e);
            } else if (message.contains("switch")) {
                return new RedisEnvironmentException.SwitchException("环境切换失败: " + message, e);
            } else {
                return new RedisEnvironmentException("环境异常: " + message, e);
            }
        }

        // 默认为一般Redis异常
        return new RedisException("Redis异常: " + message, e);
    }

    /**
     * 确定错误类型
     *
     * @param e Redis异常
     * @return 错误类型
     */
    private RedisErrorEvent.ErrorType determineErrorType(RedisException e) {
        if (e instanceof RedisConnectionException) {
            return RedisErrorEvent.ErrorType.CONNECTION_ERROR;
        } else if (e instanceof RedisCommandException) {
            return RedisErrorEvent.ErrorType.COMMAND_ERROR;
        } else if (e instanceof RedisEnvironmentException) {
            return RedisErrorEvent.ErrorType.ENVIRONMENT_ERROR;
        } else if (e instanceof AliyunRedisException) {
            return RedisErrorEvent.ErrorType.ALIYUN_ERROR;
        } else {
            return RedisErrorEvent.ErrorType.UNKNOWN_ERROR;
        }
    }

    /**
     * 判断是否应该重新抛出异常
     *
     * @param errorType 错误类型
     * @return 是否重新抛出
     */
    private boolean shouldRethrow(RedisErrorEvent.ErrorType errorType) {
        // 连接超时等可恢复错误不需要重新抛出，由重连机制处理
        // 其他错误需要抛出给上层处理
        return errorType != RedisErrorEvent.ErrorType.CONNECTION_ERROR;
    }
}
